5분만에 읽는 도커 기본 – 도커 데몬, 오케스트레이션, 도커 스웜
안녕하세요 클래스메소드의 수재입니다.
저번 글에서 정리했던 도커의 개요와 명령어에 이어서 내용을 정리해보았습니다.
도커 데몬
- 도커는 Server-Client 아키텍쳐
- 컨테이너와 이미지를 관리하는 도커 서버(=
dockerd
프로세스로 작동하며 이를 도커 데몬이라고 함) - 서버에 API를 입력할 수 있도록 CLI를 제공하는 도커 클라이언트
- 컨테이너와 이미지를 관리하는 도커 서버(=
출처 : 도커 공식 페이지
dockerd
명령어로 다양한 옵션을 설정한 도커 실행 가능- 혹은 도커의 설정 파일을 수정해도 됨
- Docker Desktop for Window을 이용하는 경우 docker desktop 에서 관리
-H
옵션을 사용하면 Docker Remote API로 원격 통신 가능- WSL에서 Docker Desktop for Window을 이용하는 경우에는 다음 옵션을 활성화하면 내부에서 TCP 통신이 가능
--tlsverify
옵션으로 TLS 보안을 적용할 수 있음dockerd --tlsverify \ --tlscacert={ca 경로} \ --tlscert={cert 경로} \ --tlskey={key 경로} \ -H localhost:2376 \ ~~
DOCKER_CERT_PATH , DOCKER_TLS_VERIFY
등의 환경 변수를 설정하면 평소에 편하게 이용 가능
--storage-driver
옵션으로 도커의 스토리지 드라이버를 변경 가능dockerd --storage-driver={OverlayFS, AUFS, Btrfs, Devicemapper, VFS, ZFS}
- 변경 후의 드라이버가 이전 드라이버와 다른 경우 이전의 이미지와 컨테이너는 사용 할 수 없음
- 스토리지 드라이버는 CoW 또는 RoW 방식을 사용
- 덕분에 스냅샷 파일을 불변 상태로 유지할 수 있음
- 데몬의
-D
옵션으로 디버그 모드를 활성화 할 수 있음dockerd -D
- 서비스로 구동했을 때는 로그 파일을 따로 찾아보자
- 혹은 도커 서비스의 커맨드로도 확인 가능
- 도커 데몬의 이벤트 실시간 스트림
docker events {--filter 'type=image/volume..'}
docker system events
- 실행 중인 모든 컨테이너 자원 사용량을 실시간 스트림
docker stats
- 한번만 보고 싶다면
--no-stream
옵션을 추가
- 도커에서 사용하고 있는 이미지, 컨테이너, 로컬 볼륨에 관한 정보 출력
docker system df
- 도커 데몬의 이벤트 실시간 스트림
- CAdvisor, Prometheus, Node Exporter 등 3rd party 모니터링 도구를 이용하는 방법도 있음
- 코드로 도커를 원격 조정하고 싶은 경우 Remote API를 래핑한 라이브러리를 이용하자
오케스트레이션
- 여러 서버를 하나의 그룹으로 취급하는 클러스터를 관리하는 작업을 말함
- 스케쥴링, 서비스 디스커버리, 로드 밸런싱, 고가용성, 배포 관리 등이 가능
- 오케스트레이션 툴이 이런 기능들을 우선적으로 제공하며 툴에 따라 조금씩 기능의 차이가 있음
- 도커 스웜, 아파치 메소스, 쿠버네티스(and EKS), ECS 등을 많이 사용
도커 스웜
- 도커에서 제공하는 오케스트레이션 툴
- 도커 클래식(컨테이너로서의 스웜)은 여러 대의 도커 서버에 접근하는 하나의 단일 접근점을 제공
docker run, ps
등 일반적인 도커 명령어와 도커 API로 클러스터의 관리가 가능- 공식 문서에서도 레거시로 다루고 있으니 스웜 모드를 사용하자
- 스웜 모드는 MSA를 다루기 위한 클러스터링 기능에 중점
- 오토 스케일링, 로드 밸런싱 기능을 자체적으로 지원
- 일반적으로 스웜 모드를 더 많이 사용
- 각종 정보를 저장하고 동기화 하는 분산 코디네이터, 클러스터 내의 서버를 관리하고 제어하는 매니저, 각 서버를 제어하는 에이전트를 스웜 클래식은 별도로 실행해야 하지만 스웜 모드는 자체 내장
- 매니저 노드와 워크 노드로 구성
- 앞으로 다른 오케스트레이션 툴에서도 많이 사용되는 개념
- 워커 노드를 매니저 노드에서 관리
- 매니저 노드에서도 컨테이너가 생성될 수 있음
- 매니저 노드는 1개 이상 있어야하지만 워커 노드는 없을 수도 있음
- 매니저 노드를 다중화 하여 운영하는 것을 권장
- 홀수 개의 매니저 노드 운용을 권장
docker swarm init
명령어로 시작- 호스트의 IP가 여러 개인 경우 사용할 IP 주소를 지정해야함
docker swarm init --advertise-addr {ip address}
- 출력되는 token 값은 새로운 노드를 클러스터에 추가하기 위한 비밀키
- 기본적으로 2377 포트를 사용하며 노드 사이의 통신에 7946/tcp, 7946/udp 포트를 이용하고, 스웜이 사용하는 네트워크인 ingress 오버레이 네트워크에는 4789/tcp, 4789/udp 포트 사용
- 따라서 이 포트를 각 호스트 머신에서 열어두어야 원활한 통신 가능
docker swarm join --token {출력 token 값} {통신 IP:PORT}
으로 워커 노드 추가- 주기적으로 토큰 값을 변경하는게 안전
docker swarm join-token --rotate {worker|manager}
- 클러스터에 정상적으로 추가되었는지는
docker node ls
로 확인 - 클러스터에서 나가는건 해당 워커 노드에서
docker swarm leave
- 매니저에서는 down 상태로 인식하기 때문에 실제로 관리 대상에서 제외하려면
docker node rm {worker node name}
- 매니저 노드는
docker swarm leave --force
- 매니저에서는 down 상태로 인식하기 때문에 실제로 관리 대상에서 제외하려면
- 워커 노드를 매니저 노드로 변경하려면
docker node promote {worker node name}
- 매니저 노드를 워커 노드로 변경하려면
docker node demote {manager node name}
서비스
- 스웜 모드에서 제어하는 단위는 컨테이너가 아닌 서비스
- 같은 이미지에서 생성된 컨테이너 집합
- 서비스 내에 컨테이너는 1개 이상 존재
- 컨테이너들은 각 워커 노드와 매니저 노드에 할당되며 이 서비스 내의 컨테이너 배포 단위를 태스크(task)라고 함
- 서비스에 설정된 레플리카 수만큼의 컨테이너가 스웜 클러스터 내에 유지됨
- 운영 중 하나의 노드가 다운되면 해당 노드에서 실행되던 컨테이너는 다른 노드에서 실행
- 서비스 생성은
docker service create [--name, --replicas 등등 옵션들] {image}
- detached 모드로 실행되며 당연히 컨테이너 내부에 계속 실행되는 프로세스가 없으면 정지 > 장애로 판단해서 다시 생성 반복
- 생성한 서비스의 숫자를 늘리려면 `docker service scale {service name=원하는 레플리카 수}
- 모든 노드에 컨테이너를 반드시 하나씩 생성하는 글로벌 모드는
--mode global
을 추가docker service create --name study --mode global nginx
- 노드 간에 변수 등을 넘기기 위해서
secret
이나config
사용docker secret create {secret name} {value 혹은 value가 저장된 파일}
- 생성된 secret은 컨테이너 내부의
/run/secrets/
디렉터리에 마운트docker service create ... --secret source={생성한 secret name},target={컨테이너 내부에 저장할 이름} -e {env name}="/run/secrets/target 값} ...
docker service create --secret source=test,target=mysql_pass -e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_pass" ...
- 경로나 값 등을 직접 기입하지 말고 호스트의 환경 변수 등을 이용하자
docker config create {config name} {value 혹은 value가 저장된 파일}
- 입력된 값은 base64로 인코딩 됨
- `docker service create ... --config source={생성한 config name},target=
- 서비스의 업데이트는
docker service update --image {업데이트 대상 이미지} {service name}
- 자체적으로 롤링 업데이트를 지원
- 서비스를 생성할 때 업데이트 주기, 동시 업데이트 컨테이너 수, 실패 대응 등을 설정할 수 있음
docker service create --replicas 4 --update-delay 15s --update-parallelism 3 --update-failure-action ...
- 롤백은
docker service rollback {service name}
- 서비스 목록은
docker service ls
- 서비스의 자세한 정보는
docker service ps {service name}
docker service inspect 혹은 docker inspect --type service
등으로도 확인 가능
- 서비스 삭제는 `docker service rm {service name}
- 실행 중인지는 상관없이 바로 삭제
- 장애 회복을 위해 다른 노드에 컨테이너가 실행된 후 노드가 정상 상태가 되더라도 실행중이던 컨테이너가 복구된 노드에 다시 할당되지 않음(rebalancing이 없음)
- scale 명령어로 컨테이너 수를 줄이고 다시 늘려야함
서비스 네트워크
- ingress 네트워크는 로드 밸런싱과 라우팅 메시에 사용
기본적으로 모든 노드가 ingress 네트워크에 연결
- 어떤 스웜 노드에 접근하더라도 서비스 내의 컨테이너에 접근할 수 있게 설정하는 라우팅 메시를 구성
- 로드 밸런싱도 담당
- 따라서 매니저 노드의 IP로 접근하더라도 다른 워커 노드의 컨테이너에 액세스 되는 경우도 있음
- 오버레이 네트워크 드라이버를 사용
- docker_gwbridge 네트워크는 오버레이 네트워크를 사용할 때 사용
- 외부로 나가는 통신 및 오버레이 네트워크의 트래픽 종단점(VTEP) 역할
- 네트워크도 생성 가능
docker network create --subnet 159.0.0.0/24 -d {overlay|bridge} {network name}
- 클러스터에 속한 노드 하나에서만 실행해도 다른 노드에 자동 적용
docker run
명령어로 스웜의 오버레이 네트워크를 사용하려면--net {netowrk name}
옵션을 사용
서비스 디스커버리
- 서비스의 컨테이너가 늘어나더라도 다른 서비스에서 해당 컨테이너를 인식할 수 있음
- 정확히는 해당 컨테이너를 하나하나 알아야하는게 아니라 해당 서비스'만'알면 되기 때문
- 각 서비스는 VIP를 가지며 내장 DNS 서버에서 어떠한 서비스 이름을 알아서 VIP로 변경
볼륨
- 컨테이너에서 볼륨을 공유한 것과 똑같이 호스트의 디렉터리 혹은 볼륨을 공유할 수 있음
- volume 타입은 다음과 같음
docker service create ... --mount type=volume,source={volume name},target={container target directory} ...
source
를 지정하지 않으면 임의의 이름을 가진 볼륨이 생성됨volume-nocopy
옵션을 사용하면 컨테이너의 파일들이 볼륨에 복사되지 않게 할 수 있음
- bind 타입은 호스트와 디렉터리를 공유할 때 사용
docker service create ... --mount type=bind,source={host target directory},target={container target directory} ...
- 하지만 이렇게 볼륨을 공유하면 모든 노드가 서비스를 할당받을 수 있는 볼륨 데이터를 가지고 있어야하기 때문에 비효율적
- 따라서 되도록이면 네트워크로 접근가능한 외부 스토리지를 이용하는게 바람직
노드 관리
- 노드의 상태(status)는 변경 가능
docker node update --availability {active/drain/pause} {node name}
- active는 컨테이너를 할당받을 수 있는 상태
- drain은 새로운 컨테이너의 할당을 받지 않으며 실행 중이던 서비스의 컨테이너는 모두 중지되고 active 상태의 노드로 다시 할당
- pause는 새로운 컨테이너의 할당을 다시 받지 않을 뿐 실행중인 컨테이너는 중지되지 않음
- 노드에는 키:밸류 형태의 라벨을 추가할 수 있음
docker node update --label-add {key}={value} {node name}
로 라벨 추가 가능
- 서비스를 생성할 때 조건(제약)을 설정할 수 있음(
--contraint
옵션)docker service create --constraint 'node.labels.env == dev' ...
- 라벨 조건
docker service create --constraint 'node.id == abd3123' ...
- 노드 아이디 조건
docker service create --constraint 'node.hostname == {host name} ...
- 호스트 네임(노드 이름) 조건
docker service create --constraint 'node.role == {manager|worker}' ...
- 역할 조건
docker service create --constraint 'engine.labels.{key} == {value} ...
- 엔진 라벨 조건
- 여러 개의 조건도 설정 가능
마무리
이것으로 docker swarm 까지 대략적으로 정리해보았습니다.
오케스트레이션 툴에 대해서는 이전에 작성했었던 글을 참고해주세요.
도커에 대해 좀 더 상세하게 알고 싶으신 분은 collabnix/dockerlabs 깃허브를 살펴보시는 것을 추천합니다.
긴 글 읽어주셔서 감사합니다.
오탈자 및 내용 피드백은 언제나 환영합니다. must01940 지메일로 연락 주시면 감사합니다!
본 블로그 게시글을 보시고 문의 사항이 있으신 분들은
클래스메소드코리아 (info@classmethod.kr)로 연락 주시면 빠른 시일 내 담당자가 회신 드릴 수 있도록 하겠습니다 !